package flex.cc.common.utils;

import flex.cc.base.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * Description:
 * Date:2021年7月22日 上午11:37:20
 * Author:PuJianMeng
 * Copyright (C) 2019 鹏达金融
 */
public class OpenApiUtil {
    protected static Logger logger = LoggerFactory.getLogger(OpenApiUtil.class);

    /**
     * RSA 生成公私钥
     */
    public static Map<String, String> generateKeyPair(int keySize) {
        try {
            Map<String, String> map = new HashMap<String, String>();
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(keySize);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            map.put("publicKey", Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()));
            map.put("privateKey", Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()));
            return map;
        } catch (Exception e) {
            logger.error("秘钥生成失败!", e.getStackTrace());
            throw new BusinessException("秘钥生成失败");
        }
    }

    public static PrivateKey readPrivateKey(String privateKey) {
        try {
            return KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (Exception e) {
            logger.error("秘钥读取失败!", e.getStackTrace());
            throw new BusinessException("秘钥读取失败");
        }
    }

    public static PublicKey readPublicKey(String publicKey) {
        try {
            return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey)));
        } catch (Exception e) {
            logger.error("秘钥读取失败!", e.getStackTrace());
            throw new BusinessException("秘钥读取失败");
        }
    }

    /**
     * 签名
     */
    public static String sign(PrivateKey privateKey, String content) {
        try {
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initSign(privateKey);
            sign.update(content.getBytes("UTF-8"));
            return Base64.getEncoder().encodeToString(sign.sign());
        } catch (Exception e) {
            logger.error("签名失败!", e.getStackTrace());
            throw new BusinessException("签名失败");
        }
    }

    /**
     * 验签
     */
    public static boolean checkSign(PublicKey publicKey, String content, String sign) {
        try {
            Signature verifySign = Signature.getInstance("SHA256withRSA");
            verifySign.initVerify(publicKey);
            verifySign.update(content.getBytes("UTF-8"));
            return verifySign.verify(Base64.getDecoder().decode(sign));
        } catch (Exception e) {
            logger.error("验签出现异常!", e.getStackTrace());
            throw new BusinessException("验签出现异常");
        }
    }

    /**
     * RSA加密 ，填充方案：RSAES-OAEP
     */
    public static String RSAEncryptOAEP(String message, PublicKey publicKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return Base64.getEncoder().encodeToString(segmentDoFinal(message.getBytes("UTF-8"), 86, cipher));
        } catch (Exception e) {
            logger.error("加密失败!", e.getStackTrace());
            throw new BusinessException("加密失败");
        }
    }

    /**
     * RSA解密 ，填充方案：RSAES-OAEP
     */
    public static String RSADecryptOAEP(String content, PrivateKey privateKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return new String(segmentDoFinal(Base64.getDecoder().decode(content), 128, cipher), "UTF-8");
        } catch (Exception e) {
            throw new BusinessException("解密失败");
        }
    }

    /**
     * 分段加解密
     */
    private static byte[] segmentDoFinal(byte[] content, int MAX_LENGTH, Cipher cipher) throws Exception {
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        byte[] cache;
        int length = content.length, offset = 0;
        while (length - offset > 0) {
            if (length - offset > MAX_LENGTH) {
                cache = cipher.doFinal(content, offset, MAX_LENGTH);
            } else {
                cache = cipher.doFinal(content, offset, length - offset);
            }
            result.write(cache, 0, cache.length);
            offset = offset + MAX_LENGTH;
        }
        return result.toByteArray();
    }

    public static void main(String[] args) {
        Map<String, String> keys = generateKeyPair(1024);
        String publicKey = keys.get("publicKey");
        String privateKey = keys.get("privateKey");
        System.out.println("生成秘钥==>> 公钥：" + publicKey);
        System.out.println("生成秘钥==>> 私钥：" + privateKey);

//		String content = "这是传输的内容信息啊啊啊啊啊";
//
//		String sign = sign(readPrivateKey(privateKey), content);
//		System.out.println("签名信息==>>" + sign);
//		System.out.println("验签结果==>>" + checkSign(readPublicKey(publicKey), content, sign));
//
//		String miwen = RSAEncryptOAEP(content, readPublicKey(publicKey));
//		System.out.println("加密报文==>>"+miwen);
//		System.out.println("解密报文==>>"+RSADecryptOAEP(miwen, readPrivateKey(privateKey)));
    }


}
